/**
 * @file
 * @brief This file implements the storage server.
 *
 * The storage server should be named "server" and should take a single
 * command line argument that refers to the configuration file.
 * 
 * The storage server should be able to communicate with the client
 * library functions declared in storage.h and implemented in storage.c.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include "utils.h"

#define MAX_LISTENQUEUELEN 20	///< The maximum number of queued connections.

//Initialize Database Structure.
struct database
{
  char table[MAX_TABLE_LEN];
  char key[MAX_KEY_LEN];
  char value[MAX_VALUE_LEN];
  struct node *next;
}

typedef struct database node;


 

/**
 * @brief Process a command from the client.
 *
 * @param sock The socket connected to the client.
 * @param cmd The command received from the client.
 * @return Returns 0 on success, -1 otherwise.
 */
int handle_command(int sock, char *cmd)
{
	LOG(("Processing command '%s'\n", cmd));

	// For now, just send back the command to the client.
	sendall(sock, cmd, strlen(cmd));
	sendall(sock, "\n", 1);

	return 0;
}

/**
 * @brief Start the storage server.
 *
 * This is the main entry point for the storage server.  It reads the
 * configuration file, starts listening on a port, and proccesses
 * commands from clients.
 */
int main(int argc, char *argv[])
{
	//Initialize Database.
   node *head;
   head = (node *)malloc(sizeof(node));
   
   // Process command line arguments.
	// This program expects exactly one argument: the config file name.
	assert(argc > 0);
	if (argc != 2) {
		printf("Usage %s <config_file>\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	char *config_file = argv[1];

	// Read the config file.
	struct config_params params;
	int status = read_config(config_file, &params);
	if (status != 0) {
		printf("Error processing config file.\n");
		exit(EXIT_FAILURE);
	}
	LOG(("Server on %s:%d\n", params.server_host, params.server_port));

	// Create a socket.
	int listensock = socket(PF_INET, SOCK_STREAM, 0);
	if (listensock < 0) {
		printf("Error creating socket.\n");
		exit(EXIT_FAILURE);
	}

	// Allow listening port to be reused if defunct.
	int yes = 1;
	status = setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
	if (status != 0) {
		printf("Error configuring socket.\n");
		exit(EXIT_FAILURE);
	}

	// Bind it to the listening port.
	struct sockaddr_in listenaddr;
	memset(&listenaddr, 0, sizeof listenaddr);
	listenaddr.sin_family = AF_INET;
	listenaddr.sin_port = htons(params.server_port);
	inet_pton(AF_INET, params.server_host, &(listenaddr.sin_addr)); // bind to local IP address
	status = bind(listensock, (struct sockaddr*) &listenaddr, sizeof listenaddr);
	if (status != 0) {
		printf("Error binding socket.\n");
		exit(EXIT_FAILURE);
	}

	// Listen for connections.
	status = listen(listensock, MAX_LISTENQUEUELEN);
	if (status != 0) {
		printf("Error listening on socket.\n");
		exit(EXIT_FAILURE);
	}

	// Listen loop.
	int wait_for_connections = 1;
	while (wait_for_connections) {
		// Wait for a connection.
		struct sockaddr_in clientaddr;
		socklen_t clientaddrlen = sizeof clientaddr;
		int clientsock = accept(listensock, (struct sockaddr*)&clientaddr, &clientaddrlen);
		if (clientsock < 0) {
			printf("Error accepting a connection.\n");
			exit(EXIT_FAILURE);
		}
		LOG(("Got a connection from %s:%d.\n", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port));
      
      // Get user authentication from client.
      LOG(("Username: \n"));
      char username[MAX_USERNAME_LEN];
      int status = recvline(clientsock, username, MAX_USERNAME_LEN); 
      LOG(("Password: \n"));
      char password[MAX_ENC_PASSWORD_LEN];
      int status = recvline(clientsock, password, MAX_ENC_PASSWORD_LEN);
      if ((strcmp(params.username, username)||(strcmp(params.password, password))!=0)
      {
        errno = ERR_AUTHENTICATION_FAILED;
        break;
      }
      else
        LOG(("Authentication Successful. \n")) 
      
      //Set table names.
      char tablenames[MAX_TABLE_LEN] = params.table;
      
     
		// Get commands from client.
		int wait_for_commands = 1;
		do {
			// Read a line from the client.
			char cmd[MAX_CMD_LEN];
         LOG(("Enter one of the following commands. \n (1) Get a record: Get <table> <key> \n (2) Insert a record: Insert <table> <key> <value> \n (3) Update an existing record: Update <table> <key> <value> \n (4) Delete a record: Delete <table> <key> <value> \n"));
         
			int status = recvline(clientsock, cmd, MAX_CMD_LEN);
			if (status != 0) {
				// Either an error occurred or the client closed the connection.
				wait_for_commands = 0;
			} else {
				// Handle the command from the client.
				int status = handle_command(clientsock, cmd);
				if (status != 0)
					wait_for_commands = 0; // Oops.  An error occured.
			}
		} while (wait_for_commands);
		
		// Close the connection with the client.
		close(clientsock);
		LOG(("Closed connection from %s:%d.\n", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port));
	}

	// Stop listening for connections.
	close(listensock);

	return EXIT_SUCCESS;
}



/*
error_no == 1    Data not found
error_no == 2    set failed
*/
#include <stdio.h>


void handle_command(int sock, char* command)
{
    char* pt;
    char* message;
    if (strcmp(*command, "GET")==0)
        result = 1;
    else if(strcmp(*command, "SET")==0)
        result = 2;
    else if(strcmp(*command, "QUERY")==0)
        result = 3;
    else 
        result = 0;
        
    
    switch(result)
    {
        case 0:
            DBG(("Error: Invalid Command %s %s %s\n"));
            break;
        case 1:
            pt = storage_Get (Key, Value);
            if(pt == Null)
                break;
            else{
*******         int stat = sendall();
                if(stat == 0)
                   DBG("Success! %s");
                else 
                   DBG("Failed! %s"); 
                 }
        case 2:
            pt = get(message);
            if(pt == NULL)
                break;
            else{
*******            pt = storage_Set(table, key, value);
                   if(pt == -1){
                       DBG("Failed! %s");
                       break;
                       }
                   else{
                       DBG("Success! %s");
                       break;
                       }
                 }
    }
}


struct Node{
   char Value[MAX_VALUE_LEN];
   char Key[MAX_KEY_LEN];
   char Table[MAX_TABLE_LEN];
   struct Node *next;
};

bool find_tableF(struct Node *ptr1,const char *table)
{ 
 while (ptr1!=NULL)
  {
   if (strcmp(table,ptr1->Table)==0)
     {
      return true;
     }
   ptr1=ptr1->next;
  }
   return false;
}

bool find_keyF(struct Node *ptr2,const char *key)
{
 while (ptr2!=NULL)
 {
  if (strcmp(key,ptr2->Key)==0)
   {
    return true;
   }
   ptr2=ptr2->next;
 }
  return false;
}

bool find_tableT(struct Node *ptr3,const char *table)
{
 if(ptr3!=NULL)
  {
   if (strcmp(table,ptr3->Table)==0)
     {
      return true;
     }
  }
   return false;
}

bool find_keyT(struct Node *ptr4const char *key)
{
 if(ptr4!=NULL)
  {
   if (strcmp(key,ptr4->Key)==0)
    {
     return true;
    }
  }
   return false;
}


char *storage_Get(const char *table,const char *key)
{ 
  struct Node *prv=head;
  char *fail=NULL;
  if (head==NULL)
    {
     DBG(("ERR_TABLE_NOT_FOUND\n"));
     return (fail);
    }
  else
    {
     bool check_tableF=find_tableF(prv,table);
     bool check_keyF=find_keyF(prv,key);
     if (check_tableF==false)
      {
       DBG(("ERR_TABLE_NOT_FOUND\n"));
       return (fail);
      }
     else if (check_tableF==true&&check_keyF==false)
      {
       DBG(("ERR_KEY_NOT_FOUND\n"));
       return (fail);
      }
     while (prv!=NULL)
      {
       bool check_tableT=find_tableT(prv,table);
       bool check_keyT=find_keyT(prv,key);
       if (check_table==true&&check_key==true)
        {
         return (prv->Value);
        }
        prv=prv->next;
      }
    }
}

void storage_Set(int i,const char *table, const char *key, const char *value)
{  
   struct Node *cur=head;
   struct Node *aft;
   if (i==2)
    {
     if (head==NULL)
      {
       strcpy(head->Table,table);
       strcpy(head->Key,key);
       strcpy(head->Value,value);
      }
     else
      {
       while (cur!=NULL)
         {
          cur=cur->next; 
         }
       strcpy(cur->Table,table);
       strcpy(cur->Key,key);
       strcpy(cur->Value,value);
      }
    }
   if (i==3) 
    {
      if (head==NULL)
       {
        DBG(("ERR_TABLE_NOT_FOUND\n"));
       }
      else
       {
        bool check_tableF=find_tableF(cur,table);
        if (heck_tableF==false)
         {
          DBG(("ERR_TABLE_NOT_FOUND\n"));
         }
        else
          {
           while (cur!=NULL)
            {
             bool check_tableT=find_tableT(cur,table);
             bool check_keyT=find_keyT(cur,key);
             if (check_table==true&&check_key==true)
              {
               strcpy(head->Value,value);
              }
             else if (check_table==true&&cur->Key==NULL)
              {
               strcpy(cur->Key,key);
               strcpy(cur->Value,value);
              }
              cur=cur->next;
            }   
       }
    }
   if (i=4)
    {
     if (cur==NULL)
      {
       DBG(("ERR_UNKNOWN\n"));
      }
     else
      {
       while (cur!=NULL)
            {
             bool check_tableT=find_tableT(cur,table);
             bool check_keyT=find_keyT(cur,key);
             if (check_table==true&&check_key==true)
              {
               if (cur->next==NULL)
                {
                  free (cur);
                  DBG(("DELETE_SUCCESS\n"));
                }
               else
                {
                 aft->next=cur->next;
                 free (cur);
                 DBG(("DELETE_SUCCESS\n"));
                }
              }
              aft=cur;
              cur=cur->next;
            }   
      }
    }
}